package org.easyx.ui.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.easyx.core.utils.ObjKit;
import org.easyx.ser.sys.entity.SysUser;
import org.easyx.ser.sys.serivce.SysResourceService;
import org.easyx.ser.sys.serivce.SysUserRoleService;
import org.easyx.ser.sys.serivce.SysUserService;
import org.easyx.ui.base.BossEasyUISessionUser;
import org.easyx.ui.util.SessionKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.mapper.EntityWrapper;

/**
 * shiro权限认证
 */
public class ShiroDbRealm extends AuthorizingRealm {
    private static final Logger LOGGER = LoggerFactory.getLogger(ShiroDbRealm.class);

    @Autowired 
    private SysUserService userService;
    @Autowired 
    private SysUserRoleService userRoleService;
    @Autowired
    private SysResourceService sysResourceService;
    
    public ShiroDbRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
        super(cacheManager, matcher);
    }
    
    /**
     * Shiro登录认证(原理：用户提交 用户名和密码  --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ---- shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) 
    		throws AuthenticationException {
        LOGGER.info("Shiro开始登录认证");
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        SysUser user = userService.selectOne(new EntityWrapper<SysUser>().eq("loginName",token.getUsername()));
        // 账号不存在
  		if (ObjKit.isEmpty(user)) {
  			throw new UnknownAccountException();
  		}
  		// 账号未启用
  		if (user.getStatus() == 1) {
  			throw new DisabledAccountException();
  		}
  		//手动添加到session中
        BossEasyUISessionUser su = SessionKit.genSessionUserByUser(user,userRoleService,sysResourceService);
         
        // 认证缓存信息: su对象不能太大，否则无法写入到request前端
        return new SimpleAuthenticationInfo(su, user.getLoginPwd(),ShiroByteSource.of(user.getSalt()), getName());
    }

	/**
     * Shiro权限认证
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
    	LOGGER.info("Shiro权限认证");
    	BossEasyUISessionUser shiroUser = (BossEasyUISessionUser) principals.getPrimaryPrincipal();
        
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(shiroUser.getRoleIds());
        info.addStringPermissions(shiroUser.getUrls());
        
        return info;
    }
    
    @Override
    public void onLogout(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
        BossEasyUISessionUser shiroUser = (BossEasyUISessionUser) principals.getPrimaryPrincipal();
        removeUserCache(shiroUser);
    }

    /**
     * 清除用户缓存
     * @param shiroUser
     */
    public void removeUserCache(BossEasyUISessionUser shiroUser){
        removeUserCache(shiroUser.getLoginName());
    }

    /**
     * 清除用户缓存
     * @param loginName
     */
    public void removeUserCache(String loginName){
        SimplePrincipalCollection principals = new SimplePrincipalCollection();
        principals.add(loginName, super.getName());
        super.clearCachedAuthenticationInfo(principals);
    }
}
